/*
 * ﻿Copyright (C) 2013-2014 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.eatestutil.container.glassfish;

import java.io.File;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Map.Entry;

import org.codehaus.cargo.container.InstalledLocalContainer;
import org.codehaus.cargo.container.configuration.LocalConfiguration;
import org.codehaus.cargo.container.installer.ZipURLInstaller;
import org.codehaus.cargo.generic.DefaultContainerFactory;
import org.codehaus.cargo.util.log.FileLogger;
import org.codehaus.cargo.util.log.LogLevel;

import com.newmainsoftech.eatestutil.container.InstalledLocalContainerWrapper;

/**
 * Helper class for setting up embedded Glassfish.<br /> 
 * 
 * @author Arata Y.
 *
 */
public class EmbeddedGlassfishConfig extends GlassfishConfig implements EmbeddedGlassfishPropertyConfig {
	public final static long DefaultContainerStartTimeout = 12 * 60 * 1000; // [ms]
	private long containerStartTimeout = EmbeddedGlassfishConfig.DefaultContainerStartTimeout; // [ms]
		public long getContainerStartTimeout() {
			return containerStartTimeout;
		}
		/**
		 * {@inheritDoc}
		 * Default to {@value #DefaultContainerStartTimeout}}[ms]. If it is necessary to change 
		 * to other than default, then this method needs to be called before invocation of 
		 * <code>{@link #prepInstalledLocalContainer()}</code> method.
		 */
		public void setContainerStartTimeout( long containerStartTimeout) {
			this.containerStartTimeout = containerStartTimeout;
		}
	/**
	 * {@inheritDoc}
	 * Glassfish is installed from URL pointed with <code>{@link #getContainerInstallerUrlStr()}</code> 
	 * method to where the return value of <code>{@link #getExtractDirPath()}</code> method points.
	 */
	public InstalledLocalContainerWrapper prepInstalledLocalContainer() throws Exception {
		InstalledLocalContainerWrapper installedLocalContainerWrapper
		= new InstalledLocalContainerWrapper();
		
		// install the container from a URL pointing to its distribution --------------------------
		final URL containerInstallerUrl = new URL( getContainerInstallerUrlStr());
		final ZipURLInstaller installer = new ZipURLInstaller( containerInstallerUrl);
				installer.setExtractDir( getExtractDirPath());
				if ( getLogger().isDebugEnabled()) {
					getLogger().debug( 
							MessageFormat.format( 
									"Downloading {0} from {1} to {2}, and installing to {3}.", 
									getContainerId(), 
									getContainerInstallerUrlStr(),
									installer.getDownloadDir(),
									getExtractDirPath())
							);
				}
			installer.getLogger().setLevel( LogLevel.DEBUG);
			installer.install();
				if ( getLogger().isDebugEnabled()) {
					getLogger().debug( 
							String.format(
									"%1$s was installed to %2$s.",
									getContainerId(), 
									installer.getHome())
							);
				}
		installedLocalContainerWrapper.setZipURLInstaller( installer);
		// ----------------------------------------------------------------------------------------
		
		// Create Cargo Container instance wrapping our physical container and start container ----
		final LocalConfiguration localConfiguration = prepLocalConfiguration();
		
		final DefaultContainerFactory defaultContainerFactory = new DefaultContainerFactory();
		final InstalledLocalContainer installedLocalContainer 
		= (InstalledLocalContainer)(defaultContainerFactory.createContainer( 
				getContainerId(), 
				getTypeOfContainer(), 
				localConfiguration));
			installedLocalContainer.setHome( installer.getHome());
			installedLocalContainer.setTimeout( getContainerStartTimeout());
			final FileLogger cargoLogger = new FileLogger( getCargoLogFile(), false);
				cargoLogger.setLevel( LogLevel.DEBUG);
			installedLocalContainer.setLogger( cargoLogger);
			
/*				final File projectClassesDir 
				= new File( ".", "target".concat( File.separator).concat( "classes"));
					installedLocalContainer.addExtraClasspath( projectClassesDir.getCanonicalPath());
				final File projectTestClassesDir
				= new File( ".", "target".concat( File.separator).concat( "test-classes"));
					installedLocalContainer.addExtraClasspath( projectTestClassesDir.getCanonicalPath());
*/
		installedLocalContainerWrapper.setInstalledLocalContainer( installedLocalContainer);
		// ----------------------------------------------------------------------------------------
			if ( getLogger().isDebugEnabled()) {
				getLogger().debug( 
						String.format(
								"Cargo wrapping %1$s is ready to start.",
								getContainerId())
						);
			}
		return installedLocalContainerWrapper;
	}
	
	/**
	 * {@inheritDoc}
	 * If <code>{@link #prepInstalledLocalContainer()}</code> method has been called before this, then 
	 * the value in the <code>Entry</code> instance being returned is set to point the root directory 
	 * of Glassfish installation.<br />
	 */
	public Entry<String, Object> getEmbeddedGlassfishInstallationRootPropertyEntry( 
			final InstalledLocalContainerWrapper installedLocalContainerWrapper) {
		Entry<String, Object> entry 
		= new Entry<String, Object>() {
			private Object value;
				@Override
				public Object setValue( final Object value) {
					this.value = value;
					return value;
				}
				@Override
				public Object getValue() {
					return value;
				}
			private final String Key = EmbeddedGlassfishConfig.EmbeddedGlassfishInstallationRootPropertyKey;
				@Override
				public String getKey() {
					return Key;
				}
		};
			entry.setValue( 
					installedLocalContainerWrapper.getZipURLInstaller().getHome()
					.concat( File.separator).concat( "glassfish"));
		return entry;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Entry<String, Object> getEmbeddedGlassfishInstanceRootPropertyEntry( 
			final String instanceRootDirPath) {
		Entry<String, Object> entry 
		= new Entry<String, Object>() {
			private Object value;
				@Override
				public Object setValue( final Object value) {
					this.value = value;
					return value;
				}
				@Override
				public Object getValue() {
					return value;
				}
			private final String Key = EmbeddedGlassfishConfig.EmbeddedGlassfishInstanceRootPropertyKey;
				@Override
				public String getKey() {
					return Key;
				}
		};
			entry.setValue( instanceRootDirPath);
		return entry;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Entry<String, Object> getEmbeddedGlassfishConfigurationFilePropertyEntry(
			final String configurationFilePath) {
		Entry<String, Object> entry 
		= new Entry<String, Object>() {
			private Object value;
				@Override
				public Object setValue( final Object value) {
					this.value = value;
					return value;
				}
				@Override
				public Object getValue() {
					return value;
				}
			private final String Key = EmbeddedGlassfishConfig.EmbeddedGlassfishConfigurationFilePropertyKey;
				@Override
				public String getKey() {
					return Key;
				}
		};
			entry.setValue( configurationFilePath);
		return entry;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Entry<String, Object> getEmbeddedGlassfishWebHttpPortPropertyEntry( final String port) {
		Entry<String, Object> entry 
		= new Entry<String, Object>() {
			private Object portStr;
				@Override
				public Object setValue( final Object value) {
					portStr = (String)value;
					return value;
				}
				@Override
				public Object getValue() {
					return portStr;
				}
			private final String Key = "org.glassfish.ejb.embedded.glassfish.web.http.port";
				@Override
				public String getKey() {
					return Key;
				}
		};
			entry.setValue( port);
		return entry;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void setKeepTemporaryFiles( boolean keep) {
		System.setProperty( 
				EmbeddedGlassfishConfig.KeepTemporaryFilesSystemPropertyKey, 
				String.valueOf( keep));
	}
}